package org.third.integration.ldap;

import com.sun.jndi.ldap.LdapName;
import com.sun.jndi.toolkit.dir.HierMemDirCtx;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.PagedResultsControl;
import javax.naming.ldap.PagedResultsResponseControl;

import java.util.Hashtable;

public class OpenLdapPageTest {

    static String searchBase = "DC=adfshpe,DC=com";
    static String searchFilter = "(&(name=*))";

    static final Logger logger = LoggerFactory.getLogger(OpenLdapPageTest.class);

    public static final void ldapQueryTest(Hashtable env) {

        LdapContext ctx = null;
        try {
            LdapName ldapName = new LdapName("ou=Groups,ou=STS,dc=hpeswlab,dc=com");
            searchBase = ldapName.toString();
            searchFilter = "objectClass=top";

            // Create the initial directory context
            ctx = new InitialLdapContext(env, null);
            com.sun.jndi.toolkit.dir.HierMemDirCtx schema=  (HierMemDirCtx) ctx.getSchema("");
            System.out.println(schema);

            SearchControls searchCtls = new SearchControls();
            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            String returnedAtts[] = { "*" };
            searchCtls.setReturningAttributes(null);
            NamingEnumeration<SearchResult> searchResultEnum = ctx.search(searchBase, searchFilter, searchCtls);
            while (searchResultEnum.hasMoreElements()) {
                SearchResult searchResult = searchResultEnum.next();
                System.out.println(searchResult.getNameInNamespace());
                System.out.println(searchResult.getClassName());
                System.out.println(searchResult.getObject());
                Attributes attributes = searchResult.getAttributes();
                for (NamingEnumeration<? extends Attribute> nameIterator = attributes.getAll(); nameIterator.hasMore();) {
                    Attribute attribute = nameIterator.next();
                    System.out.println(String.format("  %s=%s", attribute.getID(), attribute.getAll()));

                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ctx.close();
            } catch (NamingException e) {
                e.printStackTrace();
            }
        }
    }

    public static final void ldapPagedQueryTest(Hashtable env) {
        searchBase = "ou=Groups,dc=my-domain,dc=com";
        searchFilter = "cn=*";
        LdapContext ctx = null;
        try {

            // Create the initial directory context
            ctx = new InitialLdapContext(env, null);
            // Create the search controls
            SearchControls searchCtls = new SearchControls();

            // Specify the attributes to return
            String returnedAtts[] = { "member" };
            searchCtls.setReturningAttributes(returnedAtts);

            // Specify the search scope
            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            // Set the page size and initialize the cookie that we pass back in subsequent pages
            int pageSize = 10;
            byte[] cookie = null;

            // Request the paged results control
            Control[] ctls = new Control[] { new PagedResultsControl(pageSize, true) };
            ctx.setRequestControls(ctls);

            // initialize counter to total the results
            int totalResults = 0;

            // Search for objects using the filter
            do {
                NamingEnumeration results = ctx.search(searchBase, searchFilter, searchCtls);

                // loop through the results in each page
                while (results != null && results.hasMoreElements()) {
                    SearchResult searchResult = (SearchResult) results.next();
                    // Enumeration userEnumeration = LdapUtilities.getValuesFromAttrs(searchResult);
                    // This does move the entire result into memory, however it is only the String names of users
                    // List userList = Collections.list(userEnumeration);

                    // print out the name
                    System.out.println("name: " + searchResult.getName());
                    // increment the counter
                    totalResults++;
                }

                // examine the response controls
                cookie = parseControls(ctx.getResponseControls());
                // pass the cookie back to the server for the next page
                ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
            } while ((cookie != null) && (cookie.length != 0));
            ctx.close();

            System.out.println("Total entries: " + totalResults);
        } catch (NamingException e) {
            System.err.println("Paged Search failed." + e);
            e.printStackTrace();
        } catch (java.io.IOException e) {
            System.err.println("Paged Search failed." + e);
            e.printStackTrace();

        }
    }

    public static final void testIdmLdapOuGroupPage(Hashtable env) throws NamingException {
        searchBase = "cn=Group3,ou=Groups,dc=my-domain,dc=com";
        searchFilter = "cn=*";

        int pageSize = 100;
        // Create the initial directory context
        InitialLdapContext context2 = new InitialLdapContext(env, null);
        InitialLdapContext context1 = new InitialLdapContext(env, null);
        // Activate paged results
        byte[] cookie = null;
        try {
            context1.setRequestControls(new Control[] { new PagedResultsControl(pageSize, Control.NONCRITICAL) });
        } catch (Exception ex) {
            logger.warn("Paging not supported, full list will be returned");
        }

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        String usernameAttrib = "cn";
        String[] attrIDs = new String[1];
        attrIDs[0] = usernameAttrib;
        searchControls.setReturningAttributes(attrIDs);
        if (searchControls == null) {
            return;
        }
        do {
            NamingEnumeration answer = null;
            try {
                answer = context1.search(searchBase, "cn=*", searchControls);
            } catch (NamingException e) {
                if (logger.isTraceEnabled()) {
                    logger.error("Unable to find group", e);
                } else {
                    logger.error("Unable to find group");
                }
                logger.debug("No LDAP group found according to the parameters provided");
            }

            if (answer != null) {
                while (answer.hasMoreElements()) {

                    SearchResult sr = null;
                    try {
                        sr = (SearchResult) answer.next();
                    } catch (NamingException e) {
                        logger.error("Unable to retrieve LDAP entries", e);
                    }

                    if (sr != null) {
                        String userKey = sr.getNameInNamespace();

                        String unAttrib = "cn";
                        String[] attribFilter = new String[] { unAttrib };
                        Attributes ldapAttribs = context2.getAttributes(userKey, attribFilter);
                        Attribute ldapAttrib = ldapAttribs.get(unAttrib);
                        if (ldapAttrib == null) {
                            logger.debug("User's " + unAttrib + " attribute is null");
                        } else {
                            String upn = (String) ldapAttrib.get();
                            logger.trace("User's Username = " + upn);
                        }

                        logger.debug("Username: " + userKey);

                    } else {
                        logger.debug("No search result found for the group");
                    }
                }
            } else {
                logger.debug("Search in LDAP returned null");
            }
            try {
                // Examine the paged results control response
                Control[] controls = context1.getResponseControls();
                if (controls != null) {
                    for (int i = 0; i < controls.length; i++) {
                        if (controls[i] instanceof PagedResultsResponseControl) {
                            PagedResultsResponseControl responseControl = (PagedResultsResponseControl) controls[i];
                            int total = responseControl.getResultSize();
                            if (total != 0) {
                                logger.debug("end of page - " + "(total : " + total);
                            } else {
                                logger.debug("end of page - " + "(total: unknown)");
                            }
                            cookie = responseControl.getCookie();
                        }
                    }
                } else {
                    logger.debug("No controls were sent from the server");
                }

                // Re-activate paged results
                context1.setRequestControls(new Control[] { new PagedResultsControl(pageSize, cookie, Control.NONCRITICAL) });
            } catch (Exception ex) {
                logger.warn("Paging not supported");
                cookie = null;
            }
        } while (cookie != null);

        try {
            // Closes this context. This method releases this context's resources immediately, instead of waiting for
            // them to be released automatically by the garbage collector.
            // Good to close it for performance reasons.
            context1.close();
        } catch (NamingException e) {
            logger.error(e.getMessage(), e);
        }
    }

    public static void main(String[] args) throws Exception {

        Hashtable env = new Hashtable();

        String adminName = "adfshpe\\gongyo1";
        String adminPassword = "1Qazxsw2";
        // String adminName =
        // "CN=PropelAdmin,OU=Propel,OU=Applications,OU=TSLabs,DC=BEL1,DC=global,DC=tslabs,DC=hpecorp,DC=net";
        // String adminPassword = "HPitsm_9";
        // env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        //
        // // set security credentials, note using simple cleartext authentication
        // env.put(Context.SECURITY_AUTHENTICATION, "simple");
        // env.put(Context.SECURITY_PRINCIPAL, adminName);
        // env.put(Context.SECURITY_CREDENTIALS, adminPassword);
        //
        // // connect to my domain controller
        //// env.put(Context.PROVIDER_URL, "ldap://sgdlitvm0769.adfshp.com:389");
        // env.put(Context.PROVIDER_URL, "ldap://SHCLITVM0624.adfshpe.com:389");
        //// env.put(Context.PROVIDER_URL, "ldap://bel1dc1.bel1.global.tslabs.hpecorp.net:389");

        // activeDirectoryQueryTest(env);
        // activeDirectoryPagedQueryTest(env);

        /////////////////////// Ldap Query
        env = new Hashtable();

        // String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";
        adminName = "cn=Manager,dc=hpeswlab,dc=com";
        adminPassword = "secret";
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

        // set security credentials, note using simple cleartext authentication
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, adminName);
        env.put(Context.SECURITY_CREDENTIALS, adminPassword);

        // connect to my domain controller
        env.put(Context.PROVIDER_URL, "ldap://16.187.188.62:389");
        ldapQueryTest(env);
        // ldapPagedQueryTest(env);
        //
        // env = new Hashtable();
        //
        // // String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";
        // adminName = "cn=manager,dc=my-domain,dc=com";
        // adminPassword = "123456";
        // env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        //
        // // set security credentials, note using simple cleartext authentication
        // env.put(Context.SECURITY_AUTHENTICATION, "simple");
        // env.put(Context.SECURITY_PRINCIPAL, adminName);
        // env.put(Context.SECURITY_CREDENTIALS, adminPassword);
        //
        // // connect to my domain controller
        // env.put(Context.PROVIDER_URL, "ldap://16.187.188.240:389");
        // testIdmLdapOuGroupPage(env);

    }

    static byte[] parseControls(Control[] controls) throws NamingException {
        byte[] cookie = null;
        if (controls != null) {
            for (int i = 0; i < controls.length; i++) {
                if (controls[i] instanceof PagedResultsResponseControl) {
                    PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
                    cookie = prrc.getCookie();
                    System.out.println(">>Next Page \n");
                }
            }
        }
        return (cookie == null) ? new byte[0] : cookie;
    }
}
